package com.detech.sbmh.base.handler;

import com.detech.sbmh.base.domain.R;
import com.detech.sbmh.base.domain.RE;
import com.detech.sbmh.base.enumtype.CodeEnum;
import com.detech.sbmh.base.enumtype.MsgEnum;
import com.detech.sbmh.base.exception.LockException;
import com.detech.sbmh.base.exception.ServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
public class ServiceExceptionHandler {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * 业务异常
     */
    @ExceptionHandler(ServiceException.class)
    public RE handleServiceException(ServiceException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.warn("请求地址'{}',业务异常'{}'", requestURI, e.getMessage());
        if(e.getCode()==null){
            return R.R(CodeEnum.logicCheck,e.getMessage(),e.getData());
        }else{
            return R.R(e.getCode(),e.getMessage(),e.getData());
        }
    }

    /**
     * 分布式锁异常
     */
    @ExceptionHandler(LockException.class)
    public RE handleServiceException(LockException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.warn("请求地址'{}',业务异常'{}'", requestURI, e.getMsg());
        return R.R(CodeEnum.busy,e.getMsg());
    }

    /**
     * 参数校验拦截
     **/
    @ExceptionHandler(value= {MethodArgumentNotValidException.class , BindException.class})
    public RE<Map> handleVaildException(Exception e){
        BindingResult bindingResult = null;
        if (e instanceof MethodArgumentNotValidException) {
            bindingResult = ((MethodArgumentNotValidException)e).getBindingResult();
        } else if (e instanceof BindException) {
            bindingResult = ((BindException)e).getBindingResult();
        }
        Map<String,String> errorMap = new HashMap<>();
        bindingResult.getFieldErrors().forEach((fieldError)->
                errorMap.put(fieldError.getField(),fieldError.getDefaultMessage())
        );
        return R.R(CodeEnum.paramError, MsgEnum.PARAM_ERROR,errorMap);
    }

    /**
     * 参数校验拦截
     **/
    @ExceptionHandler(value= {ConstraintViolationException.class})
    public RE<List> handleValidationException(Exception e){
        Set<ConstraintViolation<?>> constraintViolations = null;
        if (e instanceof ConstraintViolationException) {
            constraintViolations = ((ConstraintViolationException)e).getConstraintViolations();
        }
        Map<String,String> errorMap = new HashMap<>();
        constraintViolations.forEach(fieldError->
            errorMap.put(fieldError.getPropertyPath().toString(),fieldError.getMessage())
        );
        return R.R(CodeEnum.paramError, MsgEnum.PARAM_ERROR,errorMap);
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    @Order(Ordered.LOWEST_PRECEDENCE)
    public RE handleException(Exception e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生系统异常.", requestURI, e);
        return R.R(CodeEnum.sysError, MsgEnum.SYSTEM_ERROR);
    }

}
